import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.event.*;
import java.io.DataOutputStream;
import java.io.IOException;

import javax.swing.*;

import lejos.pc.comm.NXTCommFactory;
import lejos.pc.comm.NXTConnector;

public class LegwayControl extends JFrame implements KeyListener
{
	private JTextField typingArea;
	private static Button connect;
	private static Button disconnect;
	private static Button avoid;
	private static Button follow;
	private static NXTConnector conn;
	private static DataOutputStream dos;
	private static boolean isConnected;
	private static int commands = 0;
	private static int lastCommands = 0;
	private static final int CMD_UP = 0x1;
	private static final int CMD_DOWN = 0x2;
	private static final int CMD_LEFT = 0x4;
	private static final int CMD_RIGHT = 0x8;
	private static final int CMD_SPACE = 0x10;
	private static final int CMD_AVOID = 0x20;
	private static final int CMD_FOLLOW = 0x40;

	public LegwayControl(String name) {
		super(name);
	}

	public static void main(String[] args) {

		// Create GUI
		javax.swing.SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				createAndShowGUI();
			}
		});

		// Send data continually to avoid timeout
		while(true) {
			if(isConnected) {
				sendCommands(commands);
			}
			try {
				Thread.sleep(10000);
			} catch (InterruptedException e) { }
		}
	}

	private static synchronized void sendCommands(int commands) {
		// Send data
		if(isConnected) {
			try {
				dos.writeInt(commands);
				dos.flush();
			} catch (IOException e) {
				System.err.println(e.getMessage());
				disconnect();
			}
		}
	}

	private static void createAndShowGUI() {
		//Create and set up the window
		LegwayControl frame = new LegwayControl("Legway Controller");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.addWindowListener(new WindowAdapter()
		{
			public void windowClosing(WindowEvent e)
			{
				// Close connection
				disconnect();
			}
		});

		//Set up the content pane
		frame.addComponentsToPane();

		//Display the window
		frame.setLocationByPlatform(true);
		frame.pack();
		frame.setVisible(true);
	}

	private void addComponentsToPane() {
		ActionListener buttonListener = new ButtonListener(); 
		JPanel behaviorButtons = new JPanel();

		typingArea = new JTextField(10);
		typingArea.setEditable(false);
		typingArea.addKeyListener(this);

		connect = new Button("Connect");
		connect.setActionCommand("Connect");
		connect.addActionListener(buttonListener);
		connect.addKeyListener(this);

		disconnect = new Button("Disconnect");
		disconnect.setEnabled(false);
		disconnect.setActionCommand("Disconnect");
		disconnect.addActionListener(buttonListener);
		disconnect.addKeyListener(this);
		
		avoid = new Button("Enable Avoid Front");
		avoid.setActionCommand("Avoid Front");
		avoid.addActionListener(buttonListener);
		
		follow = new Button("Enable Follow Line");
		follow.setActionCommand("Follow Line");
		follow.addActionListener(buttonListener);

		getContentPane().add(typingArea, BorderLayout.CENTER);
		getContentPane().add(connect,BorderLayout.WEST);
		getContentPane().add(disconnect,BorderLayout.EAST);
		behaviorButtons.add(avoid,BorderLayout.WEST);
		behaviorButtons.add(follow,BorderLayout.EAST);
		getContentPane().add(behaviorButtons,BorderLayout.SOUTH);
	}

	private class ButtonListener implements ActionListener {
		public void actionPerformed(ActionEvent event) {
			if(event.getActionCommand().equals("Connect")) {
				connect();
			}
			else if(event.getActionCommand().equals("Disconnect")) {
				disconnect();
			}
			else if(event.getActionCommand().equals("Avoid Front")) {
				if((commands & CMD_AVOID) != 0) {
					avoid.setLabel("Enable Avoid Front");
					commands &= ~CMD_AVOID;
				}
				else {
					avoid.setLabel("Disable Avoid Front");
					commands |= CMD_AVOID;
				}
				sendCommands(commands);
			}
			else if(event.getActionCommand().equals("Follow Line")) {
				if((commands & CMD_FOLLOW) != 0) {
					follow.setLabel("Enable Follow Line");
					commands &= ~CMD_FOLLOW;
				}
				else {
					follow.setLabel("Disable Follow Line");
					commands |= CMD_FOLLOW;
				}
				sendCommands(commands);
			}
			typingArea.requestFocus();
			typingArea.setText(commands + "");
		}
	}

	private static void connect() {
		// Start BT connection
		conn = new NXTConnector();

		// Connect to Legway via Bluetooth
		isConnected = conn.connectTo("Legway", null, NXTCommFactory.BLUETOOTH);
		if (isConnected) { // Connection succeeded
			dos = conn.getDataOut();
			connect.setEnabled(false);
			disconnect.setEnabled(true);
			sendCommands(commands); // send commands
		}
		else { // Connection failed
			System.err.println("Failed to connect to Legway!");
		}
	}

	private static void disconnect() {
		try {
			if(dos != null)
				dos.close();
			if(conn != null)
				conn.close();
		} catch (IOException ioe) {
			System.err.println("IOException closing connection:");
			System.err.println(ioe.getMessage());
		}
		isConnected = false;
		connect.setEnabled(true);
		disconnect.setEnabled(false);
	}

	public void keyTyped(KeyEvent e) {	}

	public void keyPressed(KeyEvent e) {
		int keyCode = e.getKeyCode();

		if(keyCode == KeyEvent.VK_UP)
			commands |= CMD_UP; 
		if(keyCode == KeyEvent.VK_DOWN)
			commands |= CMD_DOWN; 
		if(keyCode == KeyEvent.VK_RIGHT)
			commands |= CMD_RIGHT; 
		if(keyCode == KeyEvent.VK_LEFT)
			commands |= CMD_LEFT; 
		if(keyCode == KeyEvent.VK_SPACE)
			commands |= CMD_SPACE;

		// Send commands if new
		if(commands != lastCommands) {
			int keys = commands; //local backup
			System.out.println("Keys: " + commands);
			sendCommands(keys);
			lastCommands = commands;
		}
	}

	public void keyReleased(KeyEvent e) {
		int keyCode = e.getKeyCode();

		if(keyCode == KeyEvent.VK_UP)
			commands &= ~CMD_UP; 
		if(keyCode == KeyEvent.VK_DOWN)
			commands &= ~CMD_DOWN;
		if(keyCode == KeyEvent.VK_RIGHT)
			commands &= ~CMD_RIGHT;
		if(keyCode == KeyEvent.VK_LEFT)
			commands &= ~CMD_LEFT;
		if(keyCode == KeyEvent.VK_SPACE)
			commands &= ~CMD_SPACE;

		// Send commands
		int keys = commands; //local backup
		System.out.println("Keys: " + commands);
		sendCommands(keys);
		lastCommands = commands;
	}
}